﻿
using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using LightCAD.MathLib;
using SkiaSharp;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Drawing.Actions
{
    internal class BasePointAction : ElementAction
    {
        private BasePointAction() { }
        public BasePointAction(IDocumentEditor docEditor)
         : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：BasePoint");
        }
        private static readonly LcCreateMethod[] CreateMethods;

        static BasePointAction()
        {
            CreateMethods = new LcCreateMethod[1];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "BasePoint",
                Description = "创建基准点",
                Steps = new LcCreateStep[]
                                                   {
                                                       new LcCreateStep { Name = "Step0", Options = "指定定位点:" },
                                                       //new LcCreateStep { Name = "Step1", Options = "指定定位点或[放弃(U)]:" },
                                                   }
            };
        }
        internal static void Initilize()
        {
            ElementActions.BlockRef = new BasePointAction();
            LcDocument.ElementActions.Add(BuiltinElementType.BasePoint, ElementActions.BlockRef);
        }
        private string BlockName { get { return "BasePoint"; } }
        private Vector2 point { get; set; }

        private PointInputer inputer { get; set; }

        public async void ExecCreate(string[] args = null)
        {
            DocumentManager.CurrentRecorder.BeginAction("BasePoint");
            var doc = this.docRt.Document;


            this.StartCreating();
            this.inputer = new PointInputer(this.docEditor);
            var curMethod = this.SetCurMethod(CreateMethods, 0);
            var step0 = this.SetCurStep(curMethod, 0);
            var result0 = await inputer.Execute(step0.Options);
            //var result0 = await inputer.Execute(step0.Options);

            if (inputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }

            // zcb: 增加Res0为空的判定
            if (result0 == null || result0.ValueX == null)
            {
                this.Cancel();
                goto End;
            }
            this.point = (Vector2)result0.ValueX;
            var lcBasePoint = doc.CreateObject<LcBasePoint>();
            lcBasePoint.Point = this.point;
            lcBasePoint.Radius = 150;
            lcBasePoint.IsFireChangedEvent = true;
            this.vportRt.ActiveElementSet.InsertElement(lcBasePoint);
        End:
            this.inputer = null;
            this.EndCreating();
            DocumentManager.CurrentRecorder.CancleAction();
        }
        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offSet)
        {
            Draw(canvas, element, Matrix3.GetTranslate(offSet));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var lcBasePoint = element as LcBasePoint;
            if (lcBasePoint == null) { return; }
            DrawCircle((lcBasePoint.Radius / 3) * 2);
            DrawCircle(lcBasePoint.Radius / 3);
            DrawLine(lcBasePoint.Point + new Vector2(0, lcBasePoint.Radius), lcBasePoint.Point - new Vector2(0, lcBasePoint.Radius));
            DrawLine(lcBasePoint.Point + new Vector2(lcBasePoint.Radius, 0), lcBasePoint.Point - new Vector2(lcBasePoint.Radius, 0));
            void DrawCircle(double Radius)
            {
                var mcenter = matrix.MultiplyPoint(lcBasePoint.Point);
                var medge = matrix.MultiplyPoint(lcBasePoint.Point + new Vector2(0, Radius));
                var mradius = Vector2.Distance(mcenter, medge);
                var center = this.vportRt.ConvertWcsToScr(mcenter).ToSKPoint();
                var radius = this.vportRt.ConvertWcsToScr(mradius);
                //lcBasePoint.Radius = radius;
                bool isDragCopy = (matrix != Matrix3.Zero);
                var pen = this.GetDrawPen(lcBasePoint);
                if (pen == Constants.defaultPen)
                {
                    //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                    using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                    {

                        canvas.DrawCircle(center, (float)radius, elePen);
                    }
                }
                else
                {
                    canvas.DrawCircle(center, (float)radius, pen);
                }
            }
            void DrawLine(Vector2 vStart, Vector2 vEnd)
            {
                var mstart = matrix.MultiplyPoint(vStart);
                var mend = matrix.MultiplyPoint(vEnd);
                var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
                var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();

                var pen = this.GetDrawPen(lcBasePoint);
                if (pen == Constants.defaultPen)
                {
                    //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                    using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                    {
                        canvas.DrawLine(start, end, elePen);
                    }
                }
                else
                {
                    canvas.DrawLine(start, end, pen);
                }
            }
        }
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var basePoint = element as LcBasePoint; //getHel
            var grips = new List<ControlGrip>();
            var gripStart = new ControlGrip
            {
                Element = basePoint,
                Name = "Point",
                Position = basePoint.Point
            };
            grips.Add(gripStart);
            return grips.ToArray();
        }
        private string _gripName;

        private Vector2 _position;
        private LcBasePoint _basePoint;

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var circle = element as LcBasePoint;

            _basePoint = circle;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                if (gripName == "Point")
                    circle.Set(point: position);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="canvas"></param>
        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_basePoint == null) return;

            DrawCircle((_basePoint.Radius / 3) * 2);
            DrawCircle(_basePoint.Radius / 3);
            void DrawCircle(double Radius)
            {
                var center = this.vportRt.ConvertWcsToScr(_basePoint.Point);
                var r = this.vportRt.ConvertWcsToScr(Radius);
                if (_gripName == "Point")
                    center = this.vportRt.ConvertWcsToScr(_position);
                canvas.DrawCircle(center.ToSKPoint(), (float)r, Constants.draggingPen);
            }

        }
        public override void DrawAuxLines(SKCanvas canvas)
        {

            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var movePoint = mp.ToSKPoint();

            DrawCircle(100);
            DrawCircle(50);
            void DrawCircle(double Radius)
            {
                var r = this.vportRt.ConvertWcsToScr(Radius);
                using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                {
                    canvas.DrawCircle(movePoint, (float)r, pen);
                }
            }
            var r = 150;
            var Wcs = this.vportRt.ConvertScrToWcs(mp);
            Vector2 start = Wcs + new Vector2(r, 0);
            Vector2 end = Wcs - new Vector2(r, 0);
            DrawLine(start, end);
            start = Wcs + new Vector2(0, r);
            end = Wcs - new Vector2(0, r);
            DrawLine(start, end);

            void DrawLine(Vector2 vStart, Vector2 vEnd)
            {
                var start = this.vportRt.ConvertWcsToScr(vStart).ToSKPoint();
                var end = this.vportRt.ConvertWcsToScr(vEnd).ToSKPoint();
                using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                {
                    canvas.DrawLine(start, end, pen);
                }
            }

        }
        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>()
                       {
                           new PropertyObserver()
                               {
                                   Name = "PointX",
                                   DisplayName = "定位点 X 坐标",
                                   Getter = (ele) => (ele as LcBasePoint).Point.X,
                                   Setter = (ele, value) =>
                                       {
                                           var basePoint = (ele as LcBasePoint);
                                           var x = Convert.ToDouble(value);
                                           var sp = new Vector2(x, basePoint.Point.Y);
                                           basePoint.Set(point: sp);
                                       }
                               },
                           new PropertyObserver()
                               {
                                   Name = "PointY",
                                   DisplayName = "定位点 Y 坐标",
                                   Getter = (ele) => (ele as LcBasePoint).Point.Y,
                                   Setter = (ele, value) =>
                                       {
                                           var basePoint = (ele as LcBasePoint);
                                           var y = Convert.ToDouble(value);
                                           var sp = new Vector2(basePoint.Point.X, y);
                                           basePoint.Set(point: sp);
                                       }
                               }
                       };
        }
        public override SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2 point, bool forRef, Vector2 PrePoint = null)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var lcBasePoint = element as LcBasePoint;
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { Element = element };

            if (sscur.ObjectOn)
            {

                if (sscur.PointType.Has(SnapPointType.Endpoint))
                {
                    if ((point - lcBasePoint.Point).Length() <= maxDistance)
                    {
                        result.Point = lcBasePoint.Point;
                        result.Name = "Center";
                        Line2d line2D = new Line2d(lcBasePoint.Point, lcBasePoint.Point);
                        result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, line2D));
                    }

                }

            }

            if (result.Point != null)
                return result;
            else
                return null;
        }
    }
}
